#!/usr/bin/env python

import sys
from gl_objects import *

class State ( object ):
	def __init__ ( self, slide_name, name ):
		self.slide_name = slide_name
		self.name = name
		self.x = 0
		self.y = 0
		self.opacity = 0
		self.rotation = None
		self.scale = 1.0

		self.start = 0

	def set_data ( self, state_data, prev_state, events, start_time = 0 ):
		if not prev_state:
			prev_state = State ( "__FAKE__", "__FAKE__" )

		self.x = state_data.get ( "x", prev_state.x )
		self.y = state_data.get ( "y", prev_state.y )
		self.opacity = state_data.get ( "opacity", prev_state.opacity )
		self.scale = state_data.get ( "scale", prev_state.scale )
		self.rotation = state_data.get ( "rotation", prev_state.rotation )

		self.start = self._resolve_start ( state_data.get ( "time", 0 ), events, start_time )

		return self.start

	def _resolve_start ( self, tim, events, start_time ):
		full_name = self.slide_name + ":" + self.name

		tim = str ( tim )
		if tim.find ( ":" ) != -1:
			res = events.get ( tim, None )
			if res == None:
				sys.stderr.write ( "WARN: not found: %s for %s\n" % ( tim, full_name ) )
				res = 0
			else:
				res = int ( str ( res ), 10 )
				start_time = 0
		else:
			res = int ( tim, 10 )

		res += start_time

		events [ full_name ] = res

		return res 
			


	def __repr__ ( self ):
		return "%s:%s (x: %s, y: %s, o: %s t: %s, scale: %s - rot: %s)" % ( self.slide_name, self.name, self.x, self.y, self.opacity, self.start, self.scale, self.rotation )
		
class SlideObject ( object ):
	def __init__ ( self, data, som ):
		self.som = som

		self.name = data.get ( "name", "el%d" % len ( self.som._slides ) ).lower ()
		self.kind = data.get ( "kind", "image" )

		self.visible = 0

		self._prev_state = -1	# Previous state
		self._curr_state = 0	# Current state

		self.states = []

		if self.kind == 'click':
			self._set_states ( [ { "time" : data.get ( "time" ) } ] )
		else:
			self._set_states ( data.get ( 'states' ) )
	
		self._gl = None

		state = self.states [ 0 ]

		if self.kind == 'image':
			self._gl = GLImage ( state.x, state.y,
					     data [ 'file_name' ], 
					     opacity = state.opacity, scale = state.scale,
					     rotation = state.rotation
				   )
		elif self.kind == 'text':
			self._gl = GLText ( state.x, state.y,
					    text = data [ 'text' ],
					    font = data.get ( 'font' ),
					    font_size = data.get ( 'size', 12 ),
					    color = tuple ( data.get ( "color", ( 255, 255, 255 ) ) ),
					    opacity = state.opacity, scale = state.scale,
					    rotation = state.rotation, 
					    effects = data.get ( "effects", None )
				)
		

		if self._gl: 
			self._gl.visible = 0

	def _set_states ( self, states ):
		if not states:
			states = []

		# Add the KILL state (the last one)
		states += [ { "name" : "__KILL__" }, {}, {} ]

		prev_state = None
		count = 0
		start_time = 0
		for state in states:
			t = State ( self.name, state.get ( "name", "s%d" % count ) )
			start_time = t.set_data ( state, prev_state, self.som._events, start_time )
			self.states.append ( t )
			prev_state = t
			count += 1

		self._len = len ( self.states ) -1

		print self.name, self.kind
		for s in self.states:
			print "\t%s" % s

	def render ( self, sec, dec ):
		cs = self._curr_state

		s1 = self.states [ cs ]
		s2 = self.states [ cs + 1 ]

		search = True
		while search:
			#print "\tS1: %s - S2: %s" % ( s1.start, s2.start )

			if sec < s1.start:
				self.visible = False
				break

			self.visible = True
			if sec > s2.start:
				s1 = s2
				cs += 1

				if cs >= self._len:
					self.visible = False
					break

				s2 = self.states [ cs + 1 ]
			else:
				search = False

		if self._gl: self._gl.visible = self.visible

		if not self.visible: return False

		if self.kind == 'click':
			if self.som._waits.get ( self.name, 0 ) == 0:
				print "CLICK: ", sec
				self.som._waits [ self.name ] = True
				return True
			else:
				return False
		
		self._curr_state = cs

		dx, dy, do, sc, ro = self._calc_vals ( s1, s2 )

		#if self.name == 'hello': print "%s: sec: %s - s1: %s - S2: %s (%s %s %s)" % ( self.name, sec, s1.name, s2.name, dx, dy, do )
		#if self.name == 'hello': print "%s: sec: %s - o: %s %s)" % ( self.name, sec, self._gl.opacity, do )

		# STIAMO BARANDO
		self._gl.x += dx
		self._gl.y += dy
		self._gl.set_opacity ( self._gl.opacity + do )
		self._gl.scale += sc
		if ro is not None: self._gl.add_rotation ( ro )
		#self._gl.opacity = 1

		self._gl.name = self.name

		return False

	def _calc_vals ( self, s1, s2 ):
		t = s2.start - s1.start

		ro = None

		if t > 0:
			dx = ( float ( s2.x ) - float ( s1.x ) ) / ( float ( t ) * 50 )
			dy = ( float ( s2.y ) - float ( s1.y ) ) / ( float ( t ) * 50 )
			do = ( float ( s2.opacity ) - float ( s1.opacity ) ) / ( float ( t ) * 50 )
			sc = ( float ( s2.scale ) - float ( s1.scale ) ) / ( float ( t ) * 49.5 )

			if s2.rotation is not None or s1.rotation is not None:
				if s1.rotation == None: s1.rotation = 0
				if s2.rotation == None: s2.rotation = 0

				ro = ( float ( s2.rotation ) - float ( s1.rotation ) ) / ( float ( t ) * 49.5 )

			#print "SCALE: s2: %s - s1: %s - sc: %s (%s - %s) - ro: %s" % ( s2.scale, s1.scale, sc, s2.start, s1.start, ro )
		else:
			dx = 0
			dy = 0
			do = 0
			sc = 0

		return ( dx, dy, do, sc, ro )

class SlideObjectManager ( object ):
	"""
	SlideObjectManager

	This class handles all objects (text, image, clicks) that appear on a single slide.
	"""
	def __init__ ( self ):
		self.clear ()

	def clear ( self ):
		self._events = {}
		#self._obj_refs = {}
		self._slides = []
		self._waits = {}

	def init_slides ( self, world ):
		for s in self._slides:
			#print s.name, s._gl
			if s._gl: world.add ( s._gl )

	def add ( self, data ):
		"""
		add ( data )
	
		Adds the slide defined in ``data`` to the current queue of in-screen objects
		"""
		slide = SlideObject ( data, self )

		#self._obj_refs [ slide ] = slide
		self._slides.append ( slide )

	def render ( self, sec, millis ):
		wait = False
		for slide in self._slides:
			wait = slide.render ( sec, millis )
			if wait: break

		return wait


